# 目标： 了解函数的工作原理
#       这个程序将计算2^3+5^2的值
#
# main中的所有东西都存在寄存器中，所以data字段没有任何东西

.section .data

.section .text

msg:
    .asciz "output: %lld\n"
#   .string "output: %lld\n"    # 这是另一种定义方法 
.globl main

main:
    push    $3          # push第二个参数
    push    $2          # push第一个参数
    call    power       # 调用函数
    add     $16, %rsp   # 移回栈指针
    push    %rax        # 保存第一个运算结果

    push    $2          # push第二个参数
    push    $5          # push第一个参数
    call    power       # 调用函数
    add     $16, %rsp   # 移回栈指针

    pop     %rbx        # 将第一个运算结果从栈中
                        # 弹出到%rbx中
    add     %rax, %rbx  # 将两个结果相加，保存到%ebx

    # printf("output: %lld\n", %rsi)
    mov     $0, %rax
    mov     $msg, %rdi
    mov     %rbx, %rsi
    call    printf

    # exit(0)
    mov     $0, %rdi    
    call    exit


# 目标： 计算数的N次方
#
# 输入： 第一个参数 - 底数
#       第二个参数 - 指数
#
# 输出： 计算结果
#
# NOTES： 指数必须大于等于1
#
# 变量：
#       %rbx - 保存底数
#       %rcx - 保存指数
#       -8(%rbp) - 保存当前结果
#       %rax - 临时变量

.type power, @function
power:
    push    %rbp            # 保存旧的基址寄存器
    mov     %rsp, %rbp      # 使栈指针为基址指针
    sub     $8, %esp        # 开辟空间存储本地变量

    mov     16(%rbp), %rbx  # 保存第一个参数到%rbx
    mov     24(%rbp), %rcx  # 保存第二个参数到%rcx

    mov     %rbx, -8(%rbp)  # 保存当前结果

power_loop_start:
    cmp     $1, %rcx        # 如果指数为1，结束
    je      end_power
    mov     -8(%rbp), %rax  # 将当前结果保存移到%rax
    imul    %rbx, %rax      # 当前结果乘以底数

    mov     %rax, -8(%rbp)  # 保存当前结果
    dec     %rcx            # 指数减一
    jmp     power_loop_start

end_power:
    mov     -8(%rbp), %rax  # 返回值移到%rax
    mov     %rbp, %rsp      # 重置栈指针
    pop     %rbp            # 重置基址指针
    ret

# to run this file, follow the commands below
# $ gcc -no-pie power.s
# $ ./a.out
# output: 33
